package com.story.aistory.service.impl;

import cn.hutool.core.lang.UUID;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.annotation.*;
import com.obs.services.ObsClient;
import com.obs.services.exception.ObsException;
import com.obs.services.model.PutObjectRequest;
import com.story.aistory.config.MockMultipartFile;
import com.story.aistory.domain.dto.StoryDto;
import com.story.aistory.domain.po.*;
import com.story.aistory.domain.vo.Uploader;
import com.story.aistory.enums.AppHttpCodeEnum;
import com.story.aistory.mapper.StoryMapper;
import com.story.aistory.service.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.story.aistory.utils.AppThreadLocalUtil;
import com.story.aistory.utils.BeanUtils;
import jakarta.validation.constraints.NotBlank;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import static cn.hutool.core.lang.tree.TreeUtil.build;
import static com.story.aistory.config.Coze.runWorkflow;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author hui
 * @since 2025-03-12
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class StoryServiceImpl extends ServiceImpl<StoryMapper, Story> implements IStoryService {

    private final IPageService pageService;
    private final IUsersService usersService;
    private final ILikeRecordService likeRecordService;

    // 在StoryServiceImpl中添加以下方法
// StoryServiceImpl.java
    public Result saveStory(StoryDto storyDto) {
        Users user = AppThreadLocalUtil.getUser();
        if (user == null||user.getId()==null) {
            return Result.errorResult(AppHttpCodeEnum.NEED_LOGIN);
        }
        user=usersService.getById(user.getId());
        if (storyDto == null) {
            return Result.errorResult(AppHttpCodeEnum.PARAM_REQUIRE);
        }

        try {
            JSONObject jsonObject = runWorkflow(storyDto.getInputContent());
            log.info("jsonObject:{}", jsonObject);

            // 解析基础信息（加强空值判断）
            Story story = new Story();

            // 使用自定义拷贝方法避免覆盖关键字段
            BeanUtils.copyProperties(storyDto, story);
            log.info("title:{}", jsonObject.getString("title"));
            story.setTitle(jsonObject.getString("title"));
            story.setOpen(user.getOpen());
            story.setAuthorId(user.getId());
            // 处理页面数据（增加并行流处理）
            List<Page> pages = jsonObject.getJSONArray("pages").toJavaList(Map.class)
                    .parallelStream()
                    .map(this::processPage)
                    .filter(Objects::nonNull)
                    .collect(Collectors.toList());

            // 保存故事主体（添加事务注解）
            saveStoryWithTransaction(story, pages);
            return getStoryById(story.getId());

        } catch (Exception e) {
            log.error("保存故事失败", e);
            return Result.errorResult(AppHttpCodeEnum.SERVER_ERROR);
        }
    }

    @Transactional
    protected void saveStoryWithTransaction(Story story, List<Page> pages) {
        save(story);
        pages.forEach(p -> p.setStoryId(story.getId()).setTitle(story.getTitle()) );
        pageService.saveBatch(pages);
    }

    private Page processPage(Map<String, Object> pageData) {
        try {
            Page page = new Page();
            page.setContent((String) pageData.get("content"));

            // 增强URL处理逻辑
            page.setPicUrl(processMediaUrl((String) pageData.get("picUrl"), "image"));
            page.setAudio(processMediaUrl((String) pageData.get("audio"), "audio"));

            return page;
        } catch (Exception e) {
            log.error("页面处理失败: {}", e.getMessage());
            return null;
        }
    }

    private String processMediaUrl(String url, String type) {
        if (StringUtils.isEmpty(url)) return null;

        try {
            // 提取文件名并清洗路径
            String fileName = getValidFileName(url);
            return downloadAndUpload(url, type, fileName);
        } catch (Exception e) {
            log.error("文件处理失败 [{}]: {}", url, e.getMessage());
            return null;
        }
    }

    private String downloadAndUpload(String url, String type, String fileName) throws IOException {
        Path tempDir = Files.createTempDirectory("story_dl_");
        try (InputStream in = new URL(url).openStream()) {
            // 生成安全文件名
            String safeName = fileName.replaceAll("[^a-zA-Z0-9.-]", "_");
            Path tempFile = tempDir.resolve(safeName);

            // 下载文件（限制最大尺寸）
            byte[] buffer = new byte[1024 * 1024]; // 1MB缓冲区
            try (OutputStream out = Files.newOutputStream(tempFile)) {
                int bytesRead;
                long totalBytes = 0;
                while ((bytesRead = in.read(buffer)) != -1) {
                    totalBytes += bytesRead;
                    if (totalBytes > 50 * 1024 * 1024) { // 限制50MB
                        throw new IOException("文件大小超过限制");
                    }
                    out.write(buffer, 0, bytesRead);
                }
            }

            // 上传OBS
            return uploadToObs(tempFile.toFile(), type);
        } finally {
            // 递归删除临时目录
            Files.walk(tempDir)
                    .sorted(Comparator.reverseOrder())
                    .forEach(path -> {
                        try {
                            Files.deleteIfExists(path);
                        } catch (IOException e) {
                            log.warn("临时文件清理失败: {}", path);
                        }
                    });
        }
    }

    private String getValidFileName(String url) {
//        try {
//            String path = new URL(url).getPath();
//            String baseName = path.substring(path.lastIndexOf('/') + 1);
//            return baseName.split("[?#]")[0]; // 去除查询参数
//        } catch (Exception e) {
//            return UUID.randomUUID().toString();
//        }
        if (url == null || url.isEmpty()) {
            return "default_filename";
        }
        // 移除 URL 中的查询参数和锚点
        url = url.split("\\?")[0].split("#")[0];
        // 提取最后一个斜杠后的部分作为文件名
        int lastSlashIndex = url.lastIndexOf("/");
        if (lastSlashIndex != -1) {
            String fileName = url.substring(lastSlashIndex + 1);
            // 移除文件名中的非法字符
            fileName = fileName.replaceAll("[\\\\:*?\"<>|]", "");
            return fileName;
        }
        // 移除文件名中的非法字符
        return url.replaceAll("[\\\\:*?\"<>|]", "");
    }

    private String uploadToObs(File file, String type) {
        try (FileInputStream fis = new FileInputStream(file)) {
            String objectKey ="story/" +type + "/" + LocalDate.now() + "/" + file.getName();

            PutObjectRequest request = new PutObjectRequest();
                    request.setBucketName("drawu");
                    request.setObjectKey(objectKey);
                    request.setInput(fis);
            OBS.client.putObject(request);
            return "https://drawu.obs.cn-south-1.myhuaweicloud.com/" + objectKey;
        } catch (Exception e) {
            log.error("OBS上传失败: {}", e.getMessage());
            return null;
        }
    }


    @Override
    public Result getStoryById(Integer storyId) {
        if (storyId == null){
            return Result.errorResult(AppHttpCodeEnum.PARAM_REQUIRE);
        }
        Story story = this.getById(storyId);
        if (story.getTitle() == null) {
            return Result.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        List<Page> pages = pageService.ListByStoryId(storyId);
        if (pages == null) {
            return Result.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        //查询当前用户是否对该故事点过赞
        Users user = AppThreadLocalUtil.getUser();
        if (user != null) {
            Integer userId = user.getId();
            boolean isLike = likeRecordService.isLike(userId, storyId);
            story.setLikeornot(isLike ?1:0);
        }
        StoryDto storyDto = BeanUtils.copyBean(story, StoryDto.class);
        storyDto.setPageList(pages);
        return Result.success(storyDto);
        }

    @Override
    public Result<List<StoryDto>> getStories() {
        List<Story> stories = this.list();
        Set<Integer> storyIds = stories.stream().map(Story::getId).filter(Objects::nonNull).collect(Collectors.toSet());
        //查询当前用户是否对该故事点过赞
        List<Page> pages = pageService.ListByStoryIds(storyIds);
        List<StoryDto> storyDtos = BeanUtils.copyList(stories, StoryDto.class);
        for (StoryDto storyDto : storyDtos) {
            List<Page> pageList = pages.stream().filter(page -> Objects.equals(page.getStoryId(), storyDto.getId())).collect(Collectors.toList());
            //查询当前用户是否对该故事点过赞
            Users user = AppThreadLocalUtil.getUser();
            if (user != null) {
                Integer userId = user.getId();
                boolean isLike = likeRecordService.isLike(userId, storyDto.getId());
                storyDto.setLikeornot(isLike ?1:0);
            }
            storyDto.setPageList(pageList);
        }
        return Result.success(storyDtos);
    }

    @Override
    public Result deleteStory(Integer storyId) {
        if (storyId == null) {
            return Result.errorResult(AppHttpCodeEnum.PARAM_REQUIRE);
        }
        this.removeById(storyId);
        pageService.deleteByStoryId(storyId);
        return Result.success();
    }

    @Override
    public Result updateStory(StoryDto storyDto) {
        if (storyDto.getId() == null) {
            return Result.errorResult(AppHttpCodeEnum.PARAM_REQUIRE);
        }
        this.updateById(BeanUtils.copyBean(storyDto, Story.class));
        return Result.success();
    }

    @Override
    public Result likeStory(Integer storyId, Integer type) {
        Users user = AppThreadLocalUtil.getUser();
        // : 校验参数
        if (user == null || user.getId() == null ) {
            return Result.errorResult(AppHttpCodeEnum.PARAM_REQUIRE);
        }
        Story story = getById(storyId);
        if (story == null) {
            return Result.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        if (type == 1) {
            likeRecordService.saveLikeRecord(user.getId(), storyId);
        story.setLikeNum(story.getLikeNum() + 1);}
        else {
            likeRecordService.deleteLikeRecord(user.getId(), storyId);
            story.setLikeNum(story.getLikeNum() - 1);}
        boolean b = updateById(story);
        if (!b) {
            return Result.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        return Result.success();
    }

    @Override
    public Result readStory(Integer storyId) {
        Users user = AppThreadLocalUtil.getUser();
        // : 校验参数
        if (user == null || user.getId() == null ) {
            return Result.errorResult(AppHttpCodeEnum.PARAM_REQUIRE);
        }
        Story story = getById(storyId);
        if (story == null) {
            return Result.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        story.setReadNum(story.getReadNum() + 1);
        boolean b = updateById(story);
        if (!b) {
            return Result.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        return Result.success();
    }


}

